﻿/// @author: Bruno Figueira 11234
/// @author: Luis Pereira 12784
/// @last updated: 26-01-2015

using srccsharp.controller;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;

namespace srccsharp
{
    /// <summary>
    /// Classe que cria a interface
    /// </summary>
    public partial class ui : Form
    {
        private Controller controller;

        /// <summary>
        /// Construtor da classe ui
        /// </summary>
        public ui()
        {
            InitializeComponent();
            this.controller = new Controller();
        }

        /// <summary>
        /// Método on Load da interface
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ui_Load(object sender, EventArgs e)
        {
            this.selectGraph.SelectedIndex = 0;

        }

        /// <summary>
        /// Permite dar uma ação quando o botão Load from Excel é clicado
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void loadFromExcelToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();

            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                this.controller.LoadDataFromXLS(openFileDialog.FileName);
                MessageBox.Show("Your XLS file has been sucessfully loaded!");
            }
        }

        /// <summary>
        /// Fecha o programa quando o Quit é pressionado
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void quitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        /// <summary>
        /// Faz aparecer o gráfico pretendido quando o botão Plot Graph é pressionado
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void plotGraph_Click(object sender, EventArgs e)
        {
            if (this.selectGraph.SelectedIndex >= 0 && this.anoInicial.Text.Length > 0 && this.anoFinal.Text.Length > 0)
            {

                try
                {
                    int anoInit = Int32.Parse(this.anoInicial.Text);
                    int anoFin = Int32.Parse(this.anoFinal.Text);

                    if (anoInit < anoFin)
                    {
                        Tuple<List<int>, List<float>> data = this.controller.use_plot_graphics(this.selectGraph.SelectedIndex, anoInit, anoFin);
                        this.draw_graph(this.selectGraph.SelectedIndex, data.Item1, data.Item2);
                    }
                    else 
                    {
                        MessageBox.Show("The Initial Year must be smaller than the Final Year!");
                    }

                    
                }
                catch (Exception exception)
                {
                    MessageBox.Show("Please insert a number between 1977 and 2013!");
                }


            }
            else
            {
                MessageBox.Show("Please fill in all fields before plotting a graph!");
            }
        }

        /// <summary>
        /// Função que carrega o gráfico
        /// </summary>
        /// <param name="stat">numero que define qual a estatística a ser apresentada</param>
        /// <param name="anos">lista de anos</param>
        /// <param name="dados">lista do stat pretendido</param>
        private void draw_graph(int stat, List<int> anos, List<float> dados)
        {
            Tuple<String, String, String> statStrings = this.getStringsForStat(stat);
            this.chart1.Series.Clear();
            var series1 = new Series
            {
                Name = statStrings.Item1,
                Color = System.Drawing.Color.Green,
                IsVisibleInLegend = true,
                ChartType = SeriesChartType.Line
            };

            this.chart1.Series.Add(series1);

            for (int i = 0; i < anos.Count; i++)
            {
                series1.Points.AddXY(anos.ElementAt(i), dados.ElementAt(i));
            }
            dados.RemoveAll(x => x == 0.0F);

            this.chart1.ChartAreas["ChartArea1"].AxisX.Title = statStrings.Item2;
            this.chart1.ChartAreas["ChartArea1"].AxisY.Title = statStrings.Item3;
            this.textBox_Media.Text = "" + Math.Round(dados.Average(),2);
            this.textBox_DesvioPad.Text = "" + this.CalculateStdDev(dados);
            this.textBox_Variancia.Text = "" + this.Variance(dados, dados.Average());

            this.chart1.ChartAreas["ChartArea1"].RecalculateAxesScale();
            this.chart1.Invalidate();


        }

        /// <summary>
        /// Método auxiliar que vai buscar o title, o XLabel e o YLabel do gráfico
        /// </summary>
        /// <param name="stat">numero que define qual a estatística à qual as strings devem ser apresentadas</param>
        /// <returns>Túpulo com as Strings do title, XLabel e YLabel</returns>
        private Tuple<String, String, String> getStringsForStat(int stat)
        {
            if (stat == Controller.STAT_IPC)
            {
                return new Tuple<string, string, string>("Variação dos Anos com o IPC-Global", "Anos", "IPC_Global");
            }
            else if (stat == Controller.STAT_TAXA)
            {
                return new Tuple<string, string, string>("Variacão dos Anos com a Taxa de Inflação", "Anos", "Taxa de Inflação");
            }
            else if (stat == Controller.STAT_REMUN_MIN)
            {
                return new Tuple<string, string, string>("Variação dos Anos com a Remuneração Mínima Mensal", "Anos", "Remuneração Mínima");
            }
            else if (stat == Controller.STAT_REMUN_MAX)
            {
                return new Tuple<string, string, string>("Variação dos Anos com o Remuneração Máxima Mensal", "Anos", "Remuneração Máxima");
            }
            else if (stat == Controller.STAT_EV_MIN)
            {
                return new Tuple<string, string, string>("Variação dos Anos com o Evolução das Remunerações", "Anos", "Evolução das Remunerações mínimas");
            }
            else if (stat == Controller.STAT_EV_MAX)
            {
                return new Tuple<string, string, string>("Variação dos Anos com o Evolução das Remunerações", "Anos", "Evolução das Remunerações máximas");
            }
            else if (stat == Controller.STAT_PIB)
            {
                return new Tuple<string, string, string>("Variação dos Anos com o PIB Anual", "Anos", "PIB Anual");
            }
            else if (stat == Controller.STAT_REND_NACIONAL)
            {
                return new Tuple<string, string, string>("Variação dos Anos com o Rendimento Nacional Bruto", "Anos", "Rendimento Nacional Bruto");
            }
            else if (stat == Controller.STAT_REND_DISPONIVEL)
            {
                return new Tuple<string, string, string>("Variação dos Anos com o Rendimento Disponível Bruto", "Anos", "Rendimento Disponível Bruto");
            }
            else
            {
                return new Tuple<string, string, string>("Variação dos Anos com as Remunerações Anuais", "Anos", "Remunerações Anuais");
            }
        }

        /// <summary>
        /// Função que calcula o desvio padrão da estatística pretendida.
        /// Código baseado no encontrado em: http://stackoverflow.com/questions/3141692/standard-deviation-of-generic-list
        /// </summary>
        /// <param name="values">Lista com os dados da estatística pretendida</param>
        /// <returns>Desvio padrão</returns>
        private double CalculateStdDev(List<float> values)
        {
            double ret = 0;
            if (values.Count() > 0)
            {
                //Compute the Average      
                double avg = values.Average();
                //Perform the Sum of (value-avg)_2_2      
                double sum = values.Sum(d => Math.Pow(d - avg, 2));
                //Put it all together      
                ret = Math.Sqrt((sum) / (values.Count() - 1));
            }
            return Math.Round(ret, 2);
        }

        /// <summary>
        /// Função que calcula a variância da estatística pretendida.
        /// Código baseado no encontrado em: http://www.martijnkooij.nl/2013/04/csharp-math-mean-variance-and-standard-deviation/
        /// </summary>
        /// <param name="values">Lista com os dados da estatística pretendida</param>
        /// <param name="mean">Média</param>
        /// <returns>Variância</returns>
        private double Variance(List<float> values, float average)
        {
            double variance = 0;

            for (int i = 0; i < values.Count; i++)
            {
                variance += Math.Pow((values[i] - average), 2);
            }

            return Math.Round((variance / (values.Count)), 2);
        }

    }
}
